package com.zkh.myutils.io.excel.opcpack;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.zkh.myutils.io.IOUtils;
import com.zkh.myutils.io.excel.worksheet.Sheet;
import com.zkh.myutils.io.excel.worksheet.style.StyleHandler;

/**
 * OPC打包
 * @author zkh
 */
public class OPCPackage {
	//共享字符串
	private List<String> sharedStringList = new ArrayList<>();
	//字符串计数
	private int count = 0;
	//样式处理器
	private StyleHandler styleHandler = new StyleHandler();
	
	/**
	 * 打包
	 * @param sheetList sheet表列表
	 * @param outputStream 目标输出流
	 * @return
	 * @throws IOException
	 */
	public void pack(List<Sheet> sheetList, OutputStream outputStream) throws IOException{
		//sheet名称
		List<String> nameList = sheetList.stream().map(Sheet::getName).collect(Collectors.toList());
		//创建打包流
		ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
		//打包ContentType
		packContentType(zipOutputStream, nameList.size(), 0);
		//打包_rels/.rels
		packRels(zipOutputStream);
		//打包xl/workbook.xml
		packXlWorkbook(zipOutputStream, sheetList);
		//打包sheet
		packSheet(zipOutputStream, sheetList);
		//打包样式
		packStyles(zipOutputStream, sheetList);
		//打包xl/sharedStrings.xml
		packXlSharedStrings(zipOutputStream);
		//打包docProps下的文件
		packDocProps(zipOutputStream, nameList);
		//结束流
		zipOutputStream.close();
	}

	/**
	 * 打包ContentType
	 * @param zipOutputStream 目标输出流
	 * @param sheetListSize sheet表数量
	 * @param sheetThemeSize sheet主题数量
	 * @throws IOException
	 */
	private void packContentType(ZipOutputStream zipOutputStream, int sheetListSize, int sheetThemeSize) throws IOException {
		//打包ContentType
		zipOutputStream.putNextEntry(new ZipEntry("[Content_Types].xml"));
		//获取并写入数据
		IOUtils.copyStream(ContentType.createInputStream(sheetListSize, sheetThemeSize), zipOutputStream);
	}
	
	/**
	 * 打包_rels/.rels
	 * @param zipOutputStream 目标输出流
	 * @throws IOException 
	 */
	private void packRels(ZipOutputStream zipOutputStream) throws IOException {
		//打包_rels/.rels
		zipOutputStream.putNextEntry(new ZipEntry("_rels/.rels"));
		//文本内容
		String rels = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
				+ "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"
				+ "<Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\" Target=\"docProps/app.xml\"/>"
				+ "<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\" Target=\"docProps/core.xml\"/>"
				+ "<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>"
				+ "</Relationships>";
		//写入数据
		IOUtils.copyStream(new ByteArrayInputStream(rels.getBytes()), zipOutputStream);
	}
	
	/**
	 * 打包xl/workbook.xml
	 * @param zipOutputStream  目标输出流
	 * @param sheetList sheet表数据
	 * @throws IOException 
	 */
	private void packXlWorkbook(ZipOutputStream zipOutputStream, List<Sheet> sheetList) throws IOException {
		/** 处理关系文件 **/
		//处理关系文件
		zipOutputStream.putNextEntry(new ZipEntry("xl/_rels/workbook.xml.rels"));
		//拼接字符
		StringBuilder wbr = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
		wbr.append("<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
		wbr.append("<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings\" Target=\"sharedStrings.xml\"/>");
		wbr.append("<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>");
		//遍历sheet（rId从3开始，1留给sharedStrings，2留给styles）
		for(int i=0,len=sheetList.size(); i<len; i++) {
			wbr.append("<Relationship Id=\"rId"+(i+3)+"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet"+(i+1)+".xml\"/>");
		}
		wbr.append("</Relationships>");
		//写入数据
		IOUtils.copyStream(new ByteArrayInputStream(wbr.toString().getBytes()), zipOutputStream);
		
		/** 处理workbook.xml **/
		zipOutputStream.putNextEntry(new ZipEntry("xl/workbook.xml"));
		//拼接字符
		StringBuilder wb = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
		wb.append("<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">");
		wb.append("<workbookPr/><bookViews><workbookView activeTab=\"0\"/></bookViews><sheets>");
		//遍历sheet（rId从3开始，1留给sharedStrings，2留给styles）
		for(int i=0,len=sheetList.size(); i<len; i++) {
			wb.append("<sheet name=\"" + sheetList.get(i).getName() + "\" sheetId=\"" + ( i + 1 ) + "\" r:id=\"rId" + ( i + 3 ) + "\"/>");
		}
		wb.append("</sheets></workbook>");
		//写入数据
		IOUtils.copyStream(new ByteArrayInputStream(wb.toString().getBytes()), zipOutputStream);
	}

	/**
	 * 打包xl/sharedStrings.xml
	 * @param zipOutputStream 目标输出流
	 * @throws IOException 
	 */
	private void packXlSharedStrings(ZipOutputStream zipOutputStream) throws IOException {
		//打包sharedStrings.xml
		zipOutputStream.putNextEntry(new ZipEntry("xl/sharedStrings.xml"));
		//创建样式对象
		SharedStringsXML sharedStringsXML = new SharedStringsXML(sharedStringList, count);
		//写入数据
		sharedStringsXML.writeFormatStream(zipOutputStream);
	}

	/**
	 * 打包样式
	 * @param zipOutputStream 目标输出流
	 * @param sheetList 数据，用来获取设置的样式
	 * @throws IOException 
	 */
	private void packStyles(ZipOutputStream zipOutputStream, List<Sheet> sheetList) throws IOException {
		//打包样式
		zipOutputStream.putNextEntry(new ZipEntry("xl/styles.xml"));
		//创建样式对象
		StyleXML styleXML = new StyleXML(styleHandler);
		//写入数据
		styleXML.writeFormatStream(zipOutputStream);
	}

	/**
	 * 打包sheet
	 * @param zipOutputStream 目标输出流
	 * @param sheetList 数据
	 * @throws IOException 
	 */
	private void packSheet(ZipOutputStream zipOutputStream, List<Sheet> sheetList) throws IOException {
		//遍历Sheet
		for(int i=0,len=sheetList.size(); i<len; i++) {
			//打包
			zipOutputStream.putNextEntry(new ZipEntry("xl/worksheets/sheet" + ( i + 1 ) + ".xml"));
			//生成
			SheetXML sheetXML = new SheetXML(sheetList.get(i), styleHandler);
			//写入数据
			count += sheetXML.writeFormatStream(zipOutputStream, sharedStringList, i);
		}
	}

	/**
	 * 打包docProps下的文件
	 * @param zipOutputStream 目标输出流
	 * @param sheetNameList sheet名称集合（有序）
	 * @throws IOException 
	 */
	private void packDocProps(ZipOutputStream zipOutputStream, List<String> sheetNameList) throws IOException {
		//app.xml
		zipOutputStream.putNextEntry(new ZipEntry("docProps/app.xml"));
		//写数据
		IOUtils.copyStream(DocProps.getAppInputStream(sheetNameList), zipOutputStream);
		//core.xml
		zipOutputStream.putNextEntry(new ZipEntry("docProps/core.xml"));
		//写数据
		IOUtils.copyStream(DocProps.getCoreInputStream(), zipOutputStream);
	}
}
